#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cre2.h>

#define PRINTF(...) { printf(__VA_ARGS__);         fflush(stdout); }
#define FWRITE(...) { fwrite(__VA_ARGS__, stdout); fflush(stdout); }

int main (void)
{
    cre2_regexp_t *rex = NULL;  // 正则对象指针(编译后的正则表达式)
    cre2_options_t *opt = NULL; // 选项对象指针
    const char *pattern = NULL; // 模式指针(正则表达式)

    /* 单一匹配 */
    pattern = "ciao";
    opt = cre2_opt_new(); // 创建选项对象
    cre2_opt_set_posix_syntax(opt, 1); // 启用POSIX语法

    // 创建正则对象
    rex = cre2_new(pattern, strlen(pattern), opt);

    {
        if (cre2_error_code(rex))
            exit(EXIT_FAILURE);

        cre2_string_t match; // 匹配字符串对象
        int nmatch = 1; // 匹配个数
        int e;
        const char *text = "ciao"; // 待匹配字符串
        int text_len = strlen(text);

        // 执行匹配
        e = cre2_match(rex, text, text_len, 0, text_len,
                       CRE2_UNANCHORED, &match, nmatch);
        if (1 != e)
            exit(EXIT_FAILURE);

        // 输出结果
        PRINTF("match: retval=%d, ", e);
        FWRITE(match.data, match.length, 1);
        PRINTF("\n");
    }

    // 释放内存
    cre2_delete(rex);
    cre2_opt_delete(opt);

    /* 两个分组匹配 */
    pattern = "(ciao) (hello)";
    opt = cre2_opt_new();

    rex = cre2_new(pattern, strlen(pattern), opt);

    {
        if (cre2_error_code(rex))
            exit(EXIT_FAILURE);

        int nmatch = 3;
        cre2_string_t strings[nmatch];
        cre2_range_t ranges[nmatch];
        int e;
        const char *text = "ciao hello";
        int text_len = strlen(text);

        e = cre2_match(rex, text, text_len, 0, text_len,
                       CRE2_UNANCHORED, strings, nmatch);
        if (1 != e)
            exit(EXIT_FAILURE);

        cre2_strings_to_ranges(text, ranges, strings, nmatch);

        PRINTF("full match: ");
        FWRITE(text+ranges[0].start, ranges[0].past-ranges[0].start, 1);
        PRINTF("\n");
        PRINTF("first group: ");
        FWRITE(text+ranges[1].start, ranges[1].past-ranges[1].start, 1);
        PRINTF("\n");
        PRINTF("second group: ");
        FWRITE(text+ranges[2].start, ranges[2].past-ranges[2].start, 1);
        PRINTF("\n");
    }

    cre2_delete(rex);
    cre2_opt_delete(opt);

    /* 字面量选项 */
    pattern = "(ciao) (hello)";
    opt = cre2_opt_new();
    cre2_opt_set_literal(opt, 1);
    rex = cre2_new(pattern, strlen(pattern), opt);

    {
        if (cre2_error_code(rex))
            exit(EXIT_FAILURE);

        int nmatch = 0;
        int e;
        const char *text = "(ciao) (hello)";
        int text_len = strlen(text);

        e = cre2_match(rex, text, text_len, 0, text_len,
                       CRE2_UNANCHORED, NULL, nmatch);

        PRINTF("literal match = %d\n", e);
        if (0 == e)
            exit(EXIT_FAILURE);
    }

    cre2_delete(rex);
    cre2_opt_delete(opt);

    /* 命名分组 */
    pattern = "from (?P<S>.*) to (?P<D>.*)";
    opt = cre2_opt_new();

    rex = cre2_new(pattern, strlen(pattern), opt);

    {
        if (cre2_error_code(rex))
            exit(EXIT_FAILURE);

        int nmatch = cre2_num_capturing_groups(rex) + 1;
        cre2_string_t strings[nmatch];
        int e, SIndex, DIndex;
        const char *text = "from Montreal, Canada to Lausanne, Switzerland";
        int text_len = strlen(text);

        e = cre2_match(rex, text, text_len, 0, text_len,
                       CRE2_UNANCHORED, strings, nmatch);

        if (0 == e)
            exit(EXIT_FAILURE);

        SIndex = cre2_find_named_capturing_groups(rex, "S");

        PRINTF("SIndex: ");
        FWRITE(strings[SIndex].data, strings[SIndex].length, 1);
        PRINTF("\n");

        DIndex = cre2_find_named_capturing_groups(rex, "D");

        PRINTF("DIndex: ");
        FWRITE(strings[DIndex].data, strings[DIndex].length, 1);
        PRINTF("\n");
    }

    cre2_delete(rex);
    cre2_opt_delete(opt);

    exit(EXIT_SUCCESS);
}
